﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Xml.Serialization;
using System.Diagnostics;

namespace WoTStats.ClientApplication
{
    public partial class MainWindow : Form
    {
        private Settings settings;
        private static readonly string appdata = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
        private static readonly string settingsPath = Path.Combine(appdata, "WoTStats", "wotst.dat");
        private static readonly string battleResultsPath = Path.Combine(appdata, "Wargaming.net", "WorldOfTanks", "battle_results");
        private static readonly string battleResultsBackup = Path.Combine(appdata, "WoTStats", "BattleResults");
        private static readonly string POSTURL = @"http://www.wotst.com/BattleResultsUpload/UploadBattleResults";
        List<string> backedUpFiles = new List<string>();

        private Process wotProcess;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void StartWot()
        {
            wotProcess = new Process() { EnableRaisingEvents = true };
            wotProcess.Exited += (e,s) => Application.Exit();
            wotProcess.StartInfo.FileName = settings.Path;
            wotProcess.Start();

        }

        private void StartServerStatus()
        {
            try
            {
                serverStatusEast.ServerName = "US East";
                serverStatusEast.IPAddresses = new List<string>();
                serverStatusEast.IPAddresses.Add("209.170.73.34");
                serverStatusEast.IPAddresses.Add("209.170.73.54");
                serverStatusEast.IPAddresses.Add("209.170.73.64");
                serverStatusEast.Ping();

                serverStatusWest.ServerName = "US West";
                serverStatusWest.IPAddresses = new List<string>();
                serverStatusWest.IPAddresses.Add("162.213.61.85");
                serverStatusWest.IPAddresses.Add("162.213.61.63");
                serverStatusWest.IPAddresses.Add("209.170.73.70");
                serverStatusWest.Ping();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

        private void BackupBattleResults()
        {

            foreach (string file in Directory.GetFiles(battleResultsBackup, "*.dat", SearchOption.AllDirectories))
            {
                FileInfo fi = new FileInfo(file);
                
            }

            foreach (string file in Directory.GetFiles(battleResultsPath, "*.dat", SearchOption.AllDirectories))
            {
                FileInfo fi = new FileInfo(file);
                bool ResultsConverted = ConvertResultsToJson(fi);

                if (!ResultsConverted)
                {
                    txtOutput.Text = String.Format("Failed to parse battle results: {0}{1}{2}", fi.Name, Environment.NewLine, txtOutput.Text);
                }
                else
                {
                    string NameWithOutExtension = fi.Name.Replace(fi.Extension, "");

                    if (!backedUpFiles.Contains(NameWithOutExtension))
                        backedUpFiles.Add(NameWithOutExtension);
                }
            }
        }

        private static bool ConvertResultsToJson(FileInfo file)
        {
            ServicePointManager.Expect100Continue = false;

            using (WebClient wc = new WebClient())
            {
                wc.Headers.Clear();
                wc.Headers.Add("Content-Type", "application/octet-stream");
                wc.Headers.Add("Referer", file.Name);
                wc.Headers.Add("User-Agent", "BRCC " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);

                Uri url = new Uri("http://www.vbaddict.net/br2json.php");

                try
                {
                    byte[] result = wc.UploadFile(url, "PUT", file.FullName);

                    Encoding encodeing = Encoding.Default;
                    string json = encodeing.GetString(result);

                    using (StreamWriter sw = new StreamWriter(Path.Combine(battleResultsBackup, file.Name.Replace(file.Extension, ".JSON"))))
                    {
                        sw.Write(json);
                        sw.Close();
                    }

                    return true;
                }
                catch {
                    return false;
                }
            }
        }

        private void PostResults()
        {
            foreach (string file in Directory.GetFiles(battleResultsBackup, "*.JSON"))
            {
                FileInfo fi = new FileInfo(file);

                if (!File.Exists(file.Replace(".JSON", ".uploaded")))
                {
                    string error = string.Empty;
                    string fileContents = File.ReadAllText(file);
                    bool fileUploaded = UploadData(fileContents, out error);

                    if (fileUploaded)
                    {
                        txtOutput.Text = String.Format("Uploaded: {0}{1}{2}", fi.Name, Environment.NewLine, txtOutput.Text);
                        fi.CopyTo(fi.FullName.Replace(fi.Extension, ".uploaded"));
                        fi.Delete();
                    }
                    else
                    {
                        txtOutput.Text = String.Format("Failed to upload: {0}{1}{2}{3}{4}", fi.Name, Environment.NewLine, error, Environment.NewLine, txtOutput.Text);
                    }
                }                
            }
        }

        private static bool UploadData(string data, out string error)
        {
            const string contentType = "application/json";
            error = "0";
            ServicePointManager.Expect100Continue = false;
            CookieContainer cookies = new CookieContainer();
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(POSTURL);
            webRequest.Method = "POST";
            webRequest.ContentType = contentType;
            webRequest.CookieContainer = cookies;
            string jsonData = String.Format("{{\"data\":\'{0}'}}", data);
            webRequest.ContentLength = jsonData.Length;
            webRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1";
            webRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";

            using (StreamWriter requestWriter = new StreamWriter(webRequest.GetRequestStream()))
            {
                requestWriter.Write(jsonData);
                requestWriter.Flush();
                requestWriter.Close();
            }

            try
            {
                using (StreamReader responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream()))
                {
                    string responseData = responseReader.ReadToEnd();
                    responseReader.Close();
                    webRequest.GetResponse().Close();

                    switch (responseData)
                    {
                        case "0":
                            error = string.Empty;
                            return true;
                        case "1":
                            error = "Results file is null or empty.";
                            return false;
                        default:
                            error = responseData;
                            return false;
                    }
                }
            }
            catch (Exception ex)
            {
                error = ex.Message;
            }

            return false;
        }

        private static void RemoveUploadedFiles()
        {
            foreach (string file in Directory.GetFiles(battleResultsBackup, "*.uploaded"))
            {
                File.Delete(file);
            }
        }

        #region Settings

        private void SelectCustomExePath()
        {
            PathSelection ps = new PathSelection();
            if (ps.ShowDialog() == DialogResult.OK)
            {
                settings.Path = ps.txtPath.Text;
            }
            else
            {
                MessageBox.Show("Error obtaining path... Closing application.");
                Application.Exit();
            }
        }

        private void ReadSettingsFile()
        {
            settings = new Settings();
            XmlSerializer x = new XmlSerializer(settings.GetType());

            using (StreamReader sr = new StreamReader(settingsPath))
            {
                settings = (Settings)x.Deserialize(sr);
                sr.Close();
            }
        }

        private void LoadSettings()
        {
            bool settingsRead = false;

            if (Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "WoTStats")))
            {
                if (File.Exists(settingsPath))
                {
                    try
                    {
                        ReadSettingsFile();
                        settingsRead = true;

                        nudInterval.Value = settings.Interval;
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.Message);
                    }
                }
            }
            else
            {
                Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "WoTStats"));
            }

            if (!settingsRead)
            {
                settings = new Settings() { Interval = (int)nudInterval.Value };
            }

            if (string.IsNullOrEmpty(settings.Path))
            {
                SelectCustomExePath();
            }
        }

        private void SaveSettings()
        {
            try
            {
                if (!Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "WoTStats")))
                {
                    Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "WoTStats"));
                }

                XmlSerializer x = new XmlSerializer(settings.GetType());
                using (StreamWriter sw = new StreamWriter(settingsPath))
                {
                    x.Serialize(sw, settings);
                    sw.Flush();
                    sw.Close();
                }
            }
            catch(Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

        #endregion

        #region Event Handlers

        private void MainWindow_Load(object sender, EventArgs e)
        {
            LoadSettings();
            StartServerStatus();

            if (!Directory.Exists(battleResultsBackup))
                Directory.CreateDirectory(battleResultsBackup);

            UploadTimer.Interval = settings.Interval * 60000;
            UploadTimer.Start();

            gbAdvancedOptions.Visible = false;

            try
            {
                StartWot();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                Application.Exit();
            }
        }

        private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            BackupBattleResults();
            RemoveUploadedFiles();
            SaveSettings();
            e.Cancel = false;
        }

        private void btnAdvanced_Click(object sender, EventArgs e)
        {
            btnAdvanced.Visible = false;
            gbAdvancedOptions.Visible = true;
            btnHideOptions.Visible = true;
        }

        private void btnHideOptions_Click(object sender, EventArgs e)
        {
            btnAdvanced.Visible = true;
            gbAdvancedOptions.Visible = false;
            btnHideOptions.Visible = false;
        }

        private void nudInterval_ValueChanged(object sender, EventArgs e)
        {
            settings.Interval = (int)nudInterval.Value;
            UploadTimer.Interval = settings.Interval * 60000;
        }

        private void PingTimer_Tick(object sender, EventArgs e)
        {
            serverStatusEast.Ping();
            serverStatusWest.Ping();
        }

        private void UploadTimer_Tick(object sender, EventArgs e)
        {
            BackupBattleResults();
            PostResults();
        }

        #endregion
    }
}
